#pragma once

#ifndef __CORE_SafeRefCounted_H__
#define __CORE_SafeRefCounted_H__

/*!
 * \file SafeRefCounted.h
 * 
 * \brief Contains the class declaration of the class that implements safe reference counting
 *
 * Contains the class declaration of the class that implements safe reference counting
 *
 * \author Jorge Barrio Alfonso
 * \version 1.0
 */

#include "FLOW_core/namespace.h"
#include "FLOW_core/core_types.h"

namespace CORE
{

/*!
	 * \brief Implements reference counting and nullifies all smart poionters
	 *		  that points to this object
	 *
	 * Implements reference counting and nullifies all smart poionters
	 * that points to this object
	 */
	template< typename PtrType >
	class CSafeRefCounted
	{
	public:
		//! Default constructor
		CSafeRefCounted( );

		//! Virtual destructor
		virtual ~CSafeRefCounted( );

		//! Copy constructor, does not copy reference count
		CSafeRefCounted( const CSafeRefCounted<PtrType>& ar_safe_ref_counted );

		//! Add a reference to this object
		void AddRef( PtrType& ar_smart_ptr );

		//! Substracts the passed reference from this object
		void DecRef( PtrType& ar_smart_ptr );

		//! Returns the number of references the object has on it
		u32_t GetRefCount( void ) const;

		//! Assignment operator
		CSafeRefCounted& operator = ( const CSafeRefCounted<PtrType>& ar_safe_ref_counted );

		//! Tells if the destructor of the safe ref counted object has been called
		bool_t IsDeleting( void ) const { return m_b_deleting; };

	private:
		//! Pointer to the last reference added to this object 
		//! and beginning of the list of references to this object
		PtrType* m_p_ref;

		//! Tells if the destructor of the object has been called
		bool_t m_b_deleting;
	};

	template< typename PtrType >
	CSafeRefCounted< PtrType >::CSafeRefCounted( ) : 
		  m_p_ref( NULL )
		, m_b_deleting( false )
	{
	}

	template< typename PtrType >
	CSafeRefCounted< PtrType >::~CSafeRefCounted( )
	{
		m_b_deleting = true;

		while( m_p_ref )
		{
			(*m_p_ref) = NULL;
		}
	}

	template< typename PtrType >
	CSafeRefCounted< PtrType >::CSafeRefCounted( const CSafeRefCounted<PtrType>& ar_safe_ref_counted )
	{
		//Do not copy the reference, we will be creating ghost references
	}

	template< typename PtrType >
	CSafeRefCounted< PtrType >& CSafeRefCounted< PtrType >::operator = ( const CSafeRefCounted< PtrType >& ar_safe_ref_counted )
	{
		//Do not copy the reference, we will be creating ghost references
		return *this;
	}

	template< typename PtrType >
	void CSafeRefCounted< PtrType >::AddRef( PtrType& ar_ptr )
	{
		ar_ptr.SetNext( m_p_ref );
		m_p_ref = & ar_ptr;
	}

	template< typename PtrType >
	void CSafeRefCounted< PtrType >::DecRef( PtrType& ar_ptr )
	{
		if( !m_p_ref )
			return;

		if( m_p_ref == &ar_ptr )
		{
			m_p_ref = m_p_ref->GetNext( );
			ar_ptr.SetNext( NULL );
			return;
		}

		PtrType* p_ref = m_p_ref;
		while( p_ref && p_ref->GetNext( ) && p_ref->GetNext( ) != &ar_ptr )
			p_ref = p_ref->GetNext( );

		if( p_ref && p_ref->GetNext( ) )
		{
			p_ref->SetNext( p_ref->GetNext( )->GetNext( ) );
			ar_ptr.SetNext( NULL );
		}
	}

	template< typename PtrType >
	u32_t CSafeRefCounted< PtrType >::GetRefCount( void ) const
	{
		u32_t u_ref_count( 0 );
		PtrType* p_ref = m_p_ref;
		while( p_ref )
		{
			++u_ref_count;
			p_ref = p_ref->GetNext( );
		}
		return u_ref_count;
	}

} //end namespace CORE
#endif
